<template>
  <div class="music-scanner">
    <h2>乐谱图片识别与播放</h2>
    
    <div class="scanner-container">
      <!-- 左侧 - 文件上传和音频播放区域 -->
      <div class="scanner-main">
        <!-- 文件上传区域 -->
        <div class="upload-box">
          <div class="upload-inner" :class="{ 'dragging': isDragging }" 
               @dragover.prevent="isDragging = true" 
               @dragleave.prevent="isDragging = false"
               @drop.prevent="handleFileDrop">
            <label class="custom-file-label" for="fileInput">
              <div class="upload-icon">
                <i class="fas fa-music"></i>
              </div>
              <div class="upload-text">
                <h3>选择乐谱图片</h3>
                <p>支持PNG/JPG格式，或直接拖拽文件到此处</p>
              </div>
            </label>
            <input type="file" id="fileInput" ref="fileInput" @change="previewImage" accept="image/*" />
          </div>
          
          <!-- 预览图/识别结果图 -->
          <div class="image-display" v-if="previewUrl || resultImageUrl">
            <div class="preview-container">
              <img v-if="!resultImageUrl && previewUrl" :src="previewUrl" class="preview-img" alt="预览图" @click="viewLargeImage(previewUrl)" />
              <img v-if="resultImageUrl" :src="resultImageUrl" class="result-img" alt="识别结果" @click="viewLargeImage(resultImageUrl)" />
              <p v-if="resultImageUrl" class="result-hint">图中标注了识别到的音符和符号</p>
              <div class="image-hint">点击图片查看大图</div>
            </div>
          </div>
        </div>
        
        <!-- 提交按钮 -->
        <div class="action-buttons">
          <button class="btn secondary" @click="clearUpload" v-if="previewUrl">
            取消
          </button>
          <button class="btn primary" @click="uploadImage" :disabled="isProcessing || !selectedFile" v-if="previewUrl">
            {{ isProcessing ? '识别中...' : '上传并识别' }}
          </button>
        </div>
        
        <!-- 状态提示 -->
        <div v-if="statusMessage" :class="['status', statusError ? 'error' : 'success']">
          {{ statusMessage }}
        </div>
        
        <!-- 音频播放区域 -->
        <div v-if="showResults" class="audio-box">
          <h3>乐谱音频</h3>
          <div class="audio-container">
            <audio ref="audioPlayer" controls @error="handleAudioError"></audio>
          </div>
          <div class="audio-actions">
            <button class="btn download" @click="downloadAudio">下载音频</button>
            <button class="btn export-midi" @click="exportMidi">导出MIDI</button>
            <button class="btn share" @click="shareAudio">分享音频</button>
          </div>
        </div>
      </div>
      
      <!-- 右侧 - 智能分析区域 -->
      <div class="scanner-analysis" v-if="previewUrl || resultImageUrl">
        <div class="analysis-box">
          <h3>智能分析</h3>
          
          <div class="analysis-content">
            <div v-if="isProcessing" class="analysis-loading">
              <div class="loading-spinner"></div>
              <p>正在分析乐谱...</p>
            </div>
            
            <div v-else-if="isAnalyzing" class="analysis-loading">
              <div class="loading-spinner"></div>
              <p>正在使用DeepSeek AI进行高级分析...</p>
              <small>AI智能分析中，请稍候...</small>
            </div>
            
            <div v-else-if="analysisResults.length > 0" class="analysis-results">
              <div v-for="(item, index) in analysisResults" :key="index" class="analysis-item">
                <div class="analysis-icon">
                  <i :class="item.icon"></i>
                </div>
                <div class="analysis-text">
                  <h4>{{ item.title }}</h4>
                  <p>{{ item.description }}</p>
                </div>
              </div>
            </div>
            
            <div v-else-if="previewUrl && !resultImageUrl" class="analysis-placeholder">
              <p>上传并识别乐谱后将显示分析结果</p>
            </div>
            
            <div v-else class="analysis-placeholder">
              <p>无法生成分析结果，请重试</p>
            </div>
          </div>
        </div>
      </div>
    </div>
    
    <!-- 引导功能 -->
    <teleport to="body">
      <div v-if="showGuide" class="guide-overlay">
        <div class="guide-container" :class="`guide-step-${guideStep}`">
          <div class="guide-header">
            <h3>乐谱识别引导 <span>{{ guideStep }}/{{ totalGuideSteps }}</span></h3>
            <button class="guide-close" @click="closeGuide">&times;</button>
          </div>
          
          <div class="guide-content">
            <div v-if="guideStep === 1" class="guide-step">
              <div class="guide-icon"><i class="fas fa-file-upload"></i></div>
              <h4>第一步：上传乐谱</h4>
              <p>点击上传区域或直接拖拽乐谱图片到方框中。支持PNG和JPG格式的乐谱图片。</p>
            </div>
            
            <div v-if="guideStep === 2" class="guide-step">
              <div class="guide-icon"><i class="fas fa-search"></i></div>
              <h4>第二步：识别乐谱</h4>
              <p>选择图片后，点击"上传并识别"按钮，系统将自动分析乐谱内容并生成音频。</p>
            </div>
            
            <div v-if="guideStep === 3" class="guide-step">
              <div class="guide-icon"><i class="fas fa-play-circle"></i></div>
              <h4>第三步：播放与下载</h4>
              <p>识别完成后，您可以播放生成的音频，也可以下载音频文件或导出为MIDI格式。</p>
            </div>
            
            <div v-if="guideStep === 4" class="guide-step">
              <div class="guide-icon"><i class="fas fa-chart-line"></i></div>
              <h4>第四步：查看分析</h4>
              <p>右侧面板展示了乐谱的智能分析结果，包括乐谱类型、节拍速度等信息。</p>
            </div>
          </div>
          
          <div class="guide-footer">
            <button v-if="guideStep > 1" class="btn secondary" @click="prevGuideStep">上一步</button>
            <button v-if="guideStep < totalGuideSteps" class="btn primary" @click="nextGuideStep">下一步</button>
            <button v-if="guideStep === totalGuideSteps" class="btn primary" @click="closeGuide">开始使用</button>
          </div>
        </div>
      </div>
    </teleport>
    
    <!-- 查看大图弹窗 -->
    <teleport to="body">
      <div v-if="showLargeImage" class="large-image-modal" @click="closeLargeImage">
        <div class="large-image-container">
          <img :src="largeImageSrc" alt="乐谱大图" class="large-image" />
          <button class="close-large-image" @click.stop="closeLargeImage">&times;</button>
        </div>
      </div>
    </teleport>
    
    <!-- 快速帮助按钮 -->
    <button v-if="!showGuide" class="help-button" @click="restartGuide" title="查看使用引导">
      <i class="fas fa-question-circle"></i>
    </button>
  </div>
</template>

<script>
import axios from 'axios';
import { 
  API_ENDPOINTS, 
  TMP_PATH, 
  VIEW_DETECTION_PATH
} from '@/config';  // 移除未使用的API_BASE_URL

export default {
  name: 'MusicOcrScanner',
  data() {
    return {
      selectedFile: null,
      previewUrl: null,
      audioUrl: null,
      midiUrl: null,
      resultImageUrl: null,
      statusMessage: '',
      statusError: false,
      isProcessing: false,
      isAnalyzing: false,
      showResults: false,
      audioLoaded: false,
      isDragging: false,
      analysisResults: [],
      showLargeImage: false,
      largeImageSrc: '',
      BASE_URL: process.env.VUE_APP_BASE_URL,
      showGuide: false,
      guideStep: 1,
      totalGuideSteps: 4,
      guideFirstVisit: true,
      recognitionResults: null
    };
  },
  mounted() {
    // 检查用户是否是第一次访问
    const hasVisitedScanner = localStorage.getItem('hasVisitedScanner');
    if (!hasVisitedScanner) {
      // 显示引导
      this.showGuide = true;
      // 记录已访问
      localStorage.setItem('hasVisitedScanner', 'true');
    }
    
    // 添加键盘快捷键支持
    document.addEventListener('keydown', this.handleKeydown);
  },
  beforeUnmount() {
    // 移除事件监听器
    document.removeEventListener('keydown', this.handleKeydown);
  },
  methods: {
    // 处理拖拽上传
    handleFileDrop(event) {
      this.isDragging = false;
      const files = event.dataTransfer.files;
      if (files.length > 0) {
        this.handleFile(files[0]);
      }
    },
    
    // 选择文件时预览图片
    previewImage(event) {
      const file = event.target.files[0];
      if (!file) return;
      
      this.handleFile(file);
    },
    
    // 处理文件
    handleFile(file) {
      if (!file.type.match('image.*')) {
        this.showError('请上传图片文件 (JPG/PNG)');
        return;
      }
      
      this.selectedFile = file;
      this.previewUrl = URL.createObjectURL(file);
      
      // 清除之前的结果
      this.resultImageUrl = null;
      this.audioUrl = null;
      this.showResults = false;
      this.statusMessage = '';
      this.analysisResults = [];
    },
    
    // 清除上传
    clearUpload() {
      this.selectedFile = null;
      this.previewUrl = null;
      this.resultImageUrl = null;
      this.audioUrl = null;
      this.showResults = false;
      this.statusMessage = '';
      this.analysisResults = [];
      
      if (this.$refs.fileInput) {
        this.$refs.fileInput.value = '';
      }
    },
    
    // 显示错误信息
    showError(message) {
      this.statusMessage = message;
      this.statusError = true;
      setTimeout(() => {
        this.statusMessage = '';
      }, 3000);
    },
    
    // 显示成功信息
    showSuccess(message) {
      this.statusMessage = message;
      this.statusError = false;
    },
    
    // 处理音频错误
    handleAudioError(e) {
      console.error('音频播放错误:', e);
      this.showError('音频播放失败，请重试');
    },
    
    // 上传图片并处理识别结果
    async uploadImage() {
      if (!this.selectedFile) return;
      
      this.isProcessing = true;
      this.showSuccess('正在识别乐谱并生成音频...');
      this.showResults = false;
      this.audioLoaded = false;
      this.analysisResults = [];
      
      try {
        const formData = new FormData();
        formData.append('file', this.selectedFile);
        
        // 添加用户ID（如果用户已登录）
        const userInfo = localStorage.getItem('user');
        if (userInfo) {
          const user = JSON.parse(userInfo);
          if (user && user.id) {
            formData.append('user_id', user.id);
            console.log('添加用户ID到请求:', user.id);
          }
        }
        
        // 发送请求到后端API
        const response = await axios.post(API_ENDPOINTS.UPLOAD, formData, {
          // 不再设置responseType为blob，因为现在API返回JSON
          timeout: 30000 // 增加超时时间
        });
        
        // 处理API响应
        if (response.data && response.data.success !== false) {
          // 成功响应
          this.showSuccess('识别成功!');
          
          // 设置音频URL
          if (response.data.audio_url) {
            this.audioUrl = response.data.audio_url;
          }
          
          // 设置MIDI URL
          if (response.data.files && response.data.files.midi) {
            this.midiUrl = response.data.files.midi;
          }
          
          // 设置识别结果图像URL
          if (response.data.visualization_url) {
            this.resultImageUrl = response.data.visualization_url;
          }
          
          this.showResults = true;
          
          // 记录上传ID（如果有）
          if (response.data.upload_id) {
            console.log('上传记录ID:', response.data.upload_id);
          }
          
          // 保存响应数据用于分析
          this.recognitionResults = response.data;
          
          // 生成分析结果
          await this.generateAnalysisResults();
          
          // 加载音频
          this.$nextTick(() => {
            if (this.$refs.audioPlayer && this.audioUrl) {
              this.$refs.audioPlayer.src = this.audioUrl;
              this.$refs.audioPlayer.load();  // 显式加载
              
              // 记录音频已加载
              this.audioLoaded = true;
              
              // 设置音频事件处理
              this.$refs.audioPlayer.onerror = this.handleAudioError;
            }
          });
        } else {
          // 失败响应
          console.error('服务器返回错误:', response.data);
          this.showError(response.data.message || '识别失败，请重试');
        }
      } catch (error) {
        console.error('识别失败:', error);
        this.showError('识别或播放失败，请重试！');
      } finally {
        this.isProcessing = false;
      }
    },
    
    // 生成智能分析结果 - 使用新的分析接口
    async generateAnalysisResults() {
      // 显示加载状态
      this.analysisResults = [];
      this.isAnalyzing = true; // 添加分析中状态
      
      try {
        // 检查是否有识别结果
        if (!this.recognitionResults) {
          throw new Error("没有可用的识别结果数据");
        }
        
        // 提取音符和符号数据
        const symbols = this.extractSymbolsFromResults();
        
        // 调用后端分析API
        console.log("调用分析API，使用DeepSeek进行智能分析...");
        const response = await axios.post('/music/analyze', {
          notes_and_symbols: symbols,
          user_id: this.getUserId()
        }, {
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${this.getAuthToken()}`
          },
          timeout: 30000 // 增加超时时间，因为DeepSeek API可能需要更长时间
        });
        
        if (response.data && response.data.success) {
          console.log("分析成功:", response.data.analysis);
          // 转换分析结果为前端显示格式
          const analyses = this.formatAnalysisForDisplay(response.data.analysis);
          this.analysisResults = analyses;
        } else {
          console.error('分析结果获取失败:', response.data);
          this.useBackupAnalysisResults();
        }
      } catch (error) {
        console.error('分析API调用失败:', error);
        this.useBackupAnalysisResults();
      } finally {
        this.isAnalyzing = false;
      }
    },
    
    // 从识别结果中提取符号数据
    extractSymbolsFromResults() {
      try {
        // 默认空数据结构
        const defaultData = {
          notes: [],
          clefs: [],
          key_signatures: [],
          time_signatures: ["4/4"],
          dynamic_marks: []
        };
        
        // 如果有detection_json URL，尝试解析
        if (this.recognitionResults.files && this.recognitionResults.files.detection_json) {
          // 实际项目中可能需要额外请求获取JSON内容
          console.log("检测到JSON结果URL:", this.recognitionResults.files.detection_json);
          // 此处简化处理，使用检测到的符号数
          if (this.recognitionResults.symbols) {
            defaultData.notes = this.recognitionResults.symbols
              .filter(s => s.class.includes('note'))
              .map(s => s.class);
              
            defaultData.clefs = this.recognitionResults.symbols
              .filter(s => s.class.includes('clef'))
              .map(s => s.class);
              
            defaultData.key_signatures = this.recognitionResults.symbols
              .filter(s => s.class.includes('key'))
              .map(s => s.class);
              
            defaultData.time_signatures = this.recognitionResults.symbols
              .filter(s => s.class.includes('time'))
              .map(s => s.class);
              
            defaultData.dynamic_marks = this.recognitionResults.symbols
              .filter(s => s.class.includes('dynamic'))
              .map(s => s.class);
          }
        }
        
        return defaultData;
      } catch (e) {
        console.error('提取符号数据失败:', e);
        return {
          notes: [],
          clefs: ["treble"],
          key_signatures: ["C"],
          time_signatures: ["4/4"],
          dynamic_marks: []
        };
      }
    },
    
    // 获取当前用户ID
    getUserId() {
      try {
        const userInfo = localStorage.getItem('user');
        if (userInfo) {
          const user = JSON.parse(userInfo);
          return user.id || null;
        }
      } catch (e) {
        console.error('获取用户ID失败:', e);
      }
      return null;
    },
    
    // 获取认证令牌
    getAuthToken() {
      return localStorage.getItem('token') || '';
    },
    
    // 格式化分析结果用于显示
    formatAnalysisForDisplay(analysis) {
      if (!analysis) return [];
      
      const displayCategories = [
        {
          key: 'score_type',
          title: '乐谱类型',
          icon: 'fas fa-file-audio',
          defaultValue: '钢琴五线谱'
        },
        {
          key: 'tempo_time',
          title: '节拍与速度',
          icon: 'fas fa-stopwatch',
          defaultValue: '4/4拍，中速 (Moderato)'
        },
        {
          key: 'key_signature',
          title: '调性分析',
          icon: 'fas fa-signature',
          defaultValue: 'C大调'
        },
        {
          key: 'difficulty',
          title: '难度评估',
          icon: 'fas fa-chart-line',
          defaultValue: '初级 - 中级'
        },
        {
          key: 'mood',
          title: '情感倾向',
          icon: 'fas fa-heart',
          defaultValue: '平稳舒缓，偏向抒情'
        }
      ];
      
      return displayCategories.map(category => {
        return {
          title: category.title,
          icon: category.icon,
          description: analysis[category.key] || category.defaultValue
        };
      });
    },
    
    // 尝试加载结果图像，先尝试/tmp路径，失败再尝试/static/view_detection
    async tryLoadResultImage(baseName) {
      const timestamp = Date.now();
      const tmpUrl = `${TMP_PATH}${encodeURIComponent(baseName)}_vis.jpg?t=${timestamp}`;
      const fallbackUrl = `${VIEW_DETECTION_PATH}?file=${encodeURIComponent(baseName)}_vis.jpg&t=${timestamp}`;
      
      try {
        // 尝试加载主路径图像
        await this.checkImageExists(tmpUrl);
        this.resultImageUrl = tmpUrl;
      } catch (error) {
        try {
          // 尝试加载备用路径图像
          await this.checkImageExists(fallbackUrl);
          this.resultImageUrl = fallbackUrl;
        } catch (fallbackError) {
          console.error('无法加载结果图像，两种路径都失败');
        }
      }
    },
    
    // 检查图像是否存在
    checkImageExists(url) {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => resolve();
        img.onerror = () => reject();
        img.src = url;
      });
    },
    
    // 下载音频文件
    downloadAudio() {
      if (!this.audioUrl) {
        this.showError('没有可下载的音频文件');
        return;
      }
      
      const a = document.createElement('a');
      a.href = this.audioUrl;
      a.download = '乐谱音频.wav';
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
    },
    
    // 导出MIDI
    exportMidi() {
      if (!this.audioUrl) {
        this.showError('没有可导出的音频');
        return;
      }
      
      try {
        // 检查响应中是否包含MIDI URL
        if (this.midiUrl) {
          // 通过创建一个链接元素并点击来下载MIDI
          const a = document.createElement('a');
          a.href = this.midiUrl;
          a.download = '乐谱MIDI.mid';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          this.showSuccess('MIDI导出成功！');
        } else {
          this.showError('未找到MIDI文件');
        }
      } catch (error) {
        console.error('MIDI导出失败:', error);
        this.showError('MIDI导出失败');
      }
    },
    
    // 分享音频
    shareAudio() {
      if (!this.audioUrl) {
        this.showError('没有可分享的音频');
        return;
      }
      
      try {
        // 复制音频URL到剪贴板
        navigator.clipboard.writeText(this.audioUrl)
          .then(() => {
            this.showSuccess('音频链接已复制到剪贴板！');
          })
          .catch(err => {
            console.error('复制到剪贴板失败:', err);
            this.showError('复制到剪贴板失败');
          });
      } catch (error) {
        console.error('分享音频失败:', error);
        this.showError('分享音频失败');
      }
    },
    
    // 查看大图
    viewLargeImage(src) {
      this.largeImageSrc = src;
      this.showLargeImage = true;
    },
    
    // 关闭大图
    closeLargeImage() {
      this.showLargeImage = false;
    },
    
    // 引导功能方法
    nextGuideStep() {
      if (this.guideStep < this.totalGuideSteps) {
        this.guideStep++;
        this.highlightCurrentStep();
      } else {
        this.closeGuide();
      }
    },
    
    prevGuideStep() {
      if (this.guideStep > 1) {
        this.guideStep--;
        this.highlightCurrentStep();
      }
    },
    
    closeGuide() {
      this.showGuide = false;
      this.guideStep = 1;
      // 移除所有高亮效果
      this.removeAllHighlights();
    },
    
    restartGuide() {
      this.showGuide = true;
      this.guideStep = 1;
      this.highlightCurrentStep();
    },
    
    // 处理键盘快捷键
    handleKeydown(event) {
      if (!this.showGuide) return;
      
      // ESC键关闭引导
      if (event.key === 'Escape') {
        this.closeGuide();
      }
      // 右箭头或空格键前进
      else if ((event.key === 'ArrowRight' || event.key === ' ') && this.guideStep < this.totalGuideSteps) {
        this.nextGuideStep();
      }
      // 左箭头返回
      else if (event.key === 'ArrowLeft' && this.guideStep > 1) {
        this.prevGuideStep();
      }
      // Enter键在最后一步关闭引导
      else if (event.key === 'Enter' && this.guideStep === this.totalGuideSteps) {
        this.closeGuide();
      }
    },
    
    // 高亮当前步骤对应的UI元素
    highlightCurrentStep() {
      // 首先移除所有高亮
      this.removeAllHighlights();
      
      // 根据当前步骤添加高亮
      switch(this.guideStep) {
        case 1:
          // 高亮上传区域
          this.addHighlight('.upload-inner', 'highlight-upload');
          break;
        case 2:
          // 高亮识别按钮
          this.addHighlight('.action-buttons .primary', 'highlight-recognize');
          break;
        case 3:
          // 高亮音频区域
          this.addHighlight('.audio-box', 'highlight-audio');
          break;
        case 4:
          // 高亮分析区域
          this.addHighlight('.scanner-analysis', 'highlight-analysis');
          break;
      }
    },
    
    // 添加高亮效果
    addHighlight(selector, className) {
      const element = document.querySelector(selector);
      if (element) {
        element.classList.add(className);
        
        // 如果元素不在视口内，滚动到该元素
        const rect = element.getBoundingClientRect();
        if (
          rect.bottom < 0 || 
          rect.top > window.innerHeight ||
          rect.right < 0 || 
          rect.left > window.innerWidth
        ) {
          element.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
      }
    },
    
    // 移除所有高亮效果
    removeAllHighlights() {
      const highlights = ['highlight-upload', 'highlight-recognize', 'highlight-audio', 'highlight-analysis'];
      highlights.forEach(className => {
        const elements = document.querySelectorAll(`.${className}`);
        elements.forEach(el => el.classList.remove(className));
      });
    },
    
    // 使用备用分析结果
    useBackupAnalysisResults() {
      console.log("使用备用分析结果");
      const backupAnalyses = [
        {
          title: '乐谱类型',
          description: '钢琴五线谱',
          icon: 'fas fa-file-audio'
        },
        {
          title: '节拍与速度',
          description: '4/4拍，中速 (Moderato)',
          icon: 'fas fa-stopwatch'
        },
        {
          title: '调性分析',
          description: 'C大调',
          icon: 'fas fa-signature'
        },
        {
          title: '难度评估',
          description: '初级 - 中级',
          icon: 'fas fa-chart-line'
        },
        {
          title: '情感倾向',
          description: '平静舒缓，偏向抒情',
          icon: 'fas fa-heart'
        }
      ];
      
      // 延迟一些时间再显示备用结果
      setTimeout(() => {
        this.analysisResults = backupAnalyses;
      }, 800);
    }
  }
}
</script>

<style scoped>
.music-scanner {
  max-width: 1200px; /* 增加最大宽度以适应两栏布局 */
  margin: 0 auto;
  padding: 20px;
}

h2 {
  text-align: center;
  margin-bottom: 30px;
  color: #333;
  font-weight: 600;
}

/* 两栏布局容器 */
.scanner-container {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}

.scanner-main {
  flex: 1;
  min-width: 300px; /* 最小宽度以防止在小屏幕上变得太窄 */
}

.scanner-analysis {
  width: 300px;
}

.upload-box {
  background-color: #ffffff;
  border: 1px solid #e0e7ff;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

.dark-theme .upload-box {
  background-color: #1a1a1a;
  border-color: #3a3a45;
}

.upload-inner {
  border: 2px dashed #d1d5db;
  border-radius: 10px;
  padding: 40px;
  text-align: center;
  transition: all 0.3s;
  cursor: pointer;
}

.upload-inner.dragging {
  border-color: #4f46e5;
  background-color: rgba(79, 70, 229, 0.05);
}

.upload-inner:hover {
  border-color: #4f46e5;
  background-color: rgba(79, 70, 229, 0.02);
}

.upload-icon {
  font-size: 48px;
  color: #4f46e5;
  margin-bottom: 15px;
}

.upload-text h3 {
  font-size: 18px;
  margin-bottom: 8px;
  color: #333;
}

.upload-text p {
  color: #6b7280;
  font-size: 14px;
}

input[type="file"] {
  display: none;
}

.image-display {
  margin-top: 20px;
  text-align: center;
}

.preview-container {
  display: inline-block;
  position: relative;
  max-width: 100%;
}

.preview-img, .result-img {
  max-width: 100%;
  max-height: 400px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: transform 0.2s ease;
}

.preview-img:hover, .result-img:hover {
  transform: scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.result-hint {
  margin-top: 10px;
  font-size: 14px;
  color: #6b7280;
  font-style: italic;
}

.action-buttons {
  display: flex;
  justify-content: center;
  gap: 15px;
  margin: 20px 0;
}

.btn {
  padding: 12px 24px;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s;
  border: none;
}

.btn.primary {
  background-color: #4f46e5;
  color: white;
}

.btn.primary:hover {
  background-color: #4338ca;
}

.btn.primary:disabled {
  background-color: #a5a5a5;
  cursor: not-allowed;
}

.btn.secondary {
  background-color: white;
  color: #333;
  border: 1px solid #d1d5db;
}

.btn.secondary:hover {
  background-color: #f3f4f6;
}

.status {
  text-align: center;
  padding: 12px;
  margin: 20px 0;
  border-radius: 6px;
}

.status.success {
  background-color: #ecfdf5;
  color: #047857;
}

.status.error {
  background-color: #fef2f2;
  color: #b91c1c;
}

.audio-box {
  background-color: #ffffff;
  border: 1px solid #e0e7ff;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

.dark-theme .audio-box {
  background-color: #1a1a1a;
  border-color: #3a3a45;
}

.audio-box h3 {
  text-align: center;
  margin-bottom: 20px;
  color: #333;
}

.audio-container {
  width: 100%;
  margin-bottom: 20px;
}

.audio-container audio {
  width: 100%;
}

.audio-actions {
  display: flex;
  justify-content: center;
  gap: 15px;
}

.btn.download {
  background-color: #1d4ed8;
  color: white;
}

.btn.download:hover {
  background-color: #1e40af;
}

.btn.share {
  background-color: #0f766e;
  color: white;
}

.btn.share:hover {
  background-color: #0f5259;
}

.btn.export-midi {
  background-color: #7e22ce;
  color: white;
}

.btn.export-midi:hover {
  background-color: #6b21a8;
}

/* 智能分析区域样式 */
.analysis-box {
  background-color: #ffffff;
  border: 1px solid #e0e7ff;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

.dark-theme .analysis-box {
  background-color: #1e1e24;
  border-color: #3a3a45;
}

.analysis-box h3 {
  text-align: center;
  margin-bottom: 20px;
  color: #333;
  font-weight: 600;
  padding-bottom: 10px;
  border-bottom: 1px solid #f0f0f0;
}

.dark-theme .analysis-box h3 {
  color: #e0e0e0;
  border-bottom: 1px solid #3a3a45;
}

.analysis-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 30px 0;
}

.dark-theme .analysis-loading {
  padding: 30px 0;
  background-color: #252530;
  border-radius: 8px;
  border: 1px solid #3a3a45;
}

.loading-spinner {
  border: 4px solid rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  border-top: 4px solid #4f46e5;
  width: 40px;
  height: 40px;
  animation: spin 1s linear infinite;
  margin-bottom: 15px;
}

.dark-theme .loading-spinner {
  border: 4px solid rgba(255, 255, 255, 0.1);
  border-top: 4px solid #6366f1;
}

.dark-theme .analysis-loading p {
  color: #9ca3af;
}

.analysis-results {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.dark-theme .analysis-results {
  background-color: transparent;
}

.analysis-item {
  display: flex;
  align-items: center;
  padding: 12px;
  border-radius: 8px;
  background-color: #f9fafb;
  transition: all 0.2s;
}

.dark-theme .analysis-item {
  background-color: #252530;
  border: 1px solid #3a3a45;
}

.analysis-item:hover {
  background-color: #f3f4f6;
  transform: translateY(-2px);
}

.dark-theme .analysis-item:hover {
  background-color: #2a2a35;
  transform: translateY(-2px);
}

.analysis-icon {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #e8edfb;
  border-radius: 50%;
  margin-right: 12px;
  color: #4361ee;
  font-size: 18px;
  box-shadow: 0 2px 5px rgba(67, 97, 238, 0.15);
  transition: all 0.3s ease;
}

.dark-theme .analysis-icon {
  background-color: #333340;
  color: #818cf8;
  box-shadow: 0 2px 5px rgba(67, 97, 238, 0.3);
}

.analysis-item:hover .analysis-icon {
  transform: scale(1.1);
  box-shadow: 0 3px 8px rgba(67, 97, 238, 0.25);
  background-color: #dfe6fa;
}

.dark-theme .analysis-item:hover .analysis-icon {
  transform: scale(1.1);
  box-shadow: 0 3px 8px rgba(67, 97, 238, 0.4);
  background-color: #3a3a48;
}

.analysis-text h4 {
  font-size: 14px;
  font-weight: 600;
  color: #4b5563;
  margin: 0 0 5px 0;
}

.dark-theme .analysis-text h4 {
  color: #e0e0e0;
}

.analysis-text p {
  font-size: 14px;
  color: #6b7280;
  margin: 0;
}

.dark-theme .analysis-text p {
  color: #9ca3af;
}

.analysis-placeholder {
  padding: 30px 0;
  text-align: center;
  color: #9ca3af;
  font-style: italic;
}

.dark-theme .analysis-placeholder {
  color: #9ca3af;
  background-color: #252530;
  border-radius: 8px;
  padding: 30px 15px;
  border: 1px solid #3a3a45;
}

@media (max-width: 768px) {
  .scanner-container {
    flex-direction: column;
  }
  
  .scanner-analysis {
    width: 100%;
  }
  
  .upload-inner {
    padding: 20px;
  }
  
  .action-buttons {
    flex-direction: column;
  }
  
  .analysis-box {
    position: static;
    margin-top: 20px;
  }
}

/* 大图查看样式 */
.image-hint {
  font-size: 12px;
  color: #6b7280;
  text-align: center;
  margin-top: 5px;
  font-style: italic;
}

.large-image-modal {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.9);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 200000;
  cursor: zoom-out;
  animation: fadeIn 0.3s ease;
}

.large-image-container {
  position: relative;
  max-width: 90%;
  max-height: 90%;
}

.large-image {
  max-width: 100%;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 5px 25px rgba(0, 0, 0, 0.3);
}

.close-large-image {
  position: absolute;
  top: -40px;
  right: -40px;
  width: 36px;
  height: 36px;
  background: rgba(255, 255, 255, 0.2);
  border: none;
  border-radius: 50%;
  color: white;
  font-size: 24px;
  line-height: 32px;
  cursor: pointer;
  transition: all 0.2s ease;
}

.close-large-image:hover {
  background: rgba(255, 255, 255, 0.4);
  transform: rotate(90deg);
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.dark-theme h2 {
  color: #e0e0e0;
}

.dark-theme .upload-text h3 {
  color: #e0e0e0;
}

.dark-theme .upload-text p {
  color: #aaaaaa;
}

.dark-theme .result-hint {
  color: #aaaaaa;
}

.dark-theme .image-hint {
  color: #aaaaaa;
}

.dark-theme .audio-box h3 {
  color: #e0e0e0;
}

.dark-theme .analysis-box h3 {
  color: #e0e0e0;
  border-bottom: 1px solid #3a3a45;
}

.dark-theme .analysis-text h4 {
  color: #e0e0e0;
}

.dark-theme .analysis-text p {
  color: #aaaaaa;
}

.dark-theme .analysis-placeholder {
  color: #aaaaaa;
}

.dark-theme .status.success {
  background-color: #1a1a1a;
  color: #4ade80;
}

.dark-theme .status.error {
  background-color: #1a1a1a;
  color: #f87171;
}

/* 引导功能样式 */
.guide-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.7);
  z-index: 100000;
  display: flex;
  justify-content: center;
  align-items: center;
  animation: fadeIn 0.3s ease;
}

.guide-container {
  width: 550px;
  max-width: 90%;
  background-color: white;
  border-radius: 12px;
  box-shadow: 0 5px 30px rgba(0, 0, 0, 0.3);
  overflow: hidden;
  animation: slideIn 0.4s ease;
  position: relative;
}

.guide-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 24px;
  border-bottom: 1px solid #eaeaea;
  background-color: #f8f9fa;
}

.guide-header h3 {
  font-size: 18px;
  color: #333;
  margin: 0;
  display: flex;
  align-items: center;
  font-weight: 600;
}

.guide-header h3 span {
  font-size: 14px;
  color: #6b7280;
  background-color: #e5e7eb;
  border-radius: 20px;
  padding: 2px 10px;
  margin-left: 10px;
  font-weight: 500;
}

.guide-close {
  background: none;
  border: none;
  font-size: 24px;
  color: #6b7280;
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  transition: background-color 0.2s;
}

.guide-close:hover {
  background-color: #f3f4f6;
  color: #4b5563;
}

.guide-content {
  padding: 36px 24px;
  min-height: 250px;
}

.guide-step {
  text-align: center;
  animation: fadeInUp 0.4s ease;
}

.guide-icon {
  font-size: 54px;
  color: #4f46e5;
  margin-bottom: 22px;
  animation: bounce 1s ease infinite alternate;
}

.guide-step h4 {
  font-size: 20px;
  color: #333;
  margin-bottom: 16px;
  position: relative;
  display: inline-block;
}

.guide-step h4:after {
  content: '';
  position: absolute;
  width: 100%;
  height: 2px;
  background: #4f46e5;
  bottom: -5px;
  left: 0;
  transform: scaleX(0);
  transform-origin: left;
  animation: lineGrow 0.5s 0.2s forwards;
}

.guide-step p {
  font-size: 16px;
  color: #6b7280;
  line-height: 1.6;
  max-width: 90%;
  margin: 0 auto;
}

.guide-footer {
  border-top: 1px solid #eaeaea;
  padding: 16px 24px;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

.help-button {
  position: fixed;
  bottom: 20px;
  right: 20px;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background-color: #4f46e5;
  color: white;
  border: none;
  font-size: 24px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s;
  z-index: 1000;
}

.help-button:hover {
  transform: scale(1.05);
  background-color: #4338ca;
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}

/* 高亮效果样式 */
.highlight-upload,
.highlight-recognize,
.highlight-audio,
.highlight-analysis {
  position: relative !important;
  z-index: 100001 !important;
  box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.6), 0 0 16px rgba(79, 70, 229, 0.3) !important;
  animation: pulse 1.5s infinite alternate !important;
  transition: box-shadow 0.3s ease !important;
}

@keyframes slideIn {
  from { transform: translateY(30px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fadeInUp {
  from { transform: translateY(15px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

@keyframes bounce {
  from { transform: translateY(0); }
  to { transform: translateY(-5px); }
}

@keyframes lineGrow {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@keyframes pulse {
  from { box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.6), 0 0 16px rgba(79, 70, 229, 0.3); }
  to { box-shadow: 0 0 0 6px rgba(79, 70, 229, 0.4), 0 0 24px rgba(79, 70, 229, 0.5); }
}

/* 暗黑模式适配 */
.dark-theme .guide-container {
  background-color: #1a1a1a;
  border: 1px solid #3a3a45;
}

.dark-theme .guide-header {
  background-color: #252530;
  border-color: #3a3a45;
}

.dark-theme .guide-header h3 {
  color: #e0e0e0;
}

.dark-theme .guide-header h3 span {
  background-color: #333340;
  color: #aaaaaa;
}

.dark-theme .guide-close {
  color: #aaaaaa;
}

.dark-theme .guide-close:hover {
  background-color: #333340;
  color: #e0e0e0;
}

.dark-theme .guide-step h4 {
  color: #e0e0e0;
}

.dark-theme .guide-step h4:after {
  background: #6366f1;
}

.dark-theme .guide-step p {
  color: #aaaaaa;
}

.dark-theme .guide-footer {
  border-color: #3a3a45;
}

.dark-theme .help-button {
  background-color: #4338ca;
}

.dark-theme .help-button:hover {
  background-color: #4f46e5;
}

.dark-theme .highlight-upload,
.dark-theme .highlight-recognize,
.dark-theme .highlight-audio,
.dark-theme .highlight-analysis {
  box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.6), 0 0 16px rgba(99, 102, 241, 0.3) !important;
}

@media (max-width: 768px) {
  .guide-content {
    padding: 24px 18px;
    min-height: 200px;
  }
  
  .guide-icon {
    font-size: 42px;
    margin-bottom: 16px;
  }
  
  .guide-step h4 {
    font-size: 18px;
  }
  
  .guide-step p {
    font-size: 14px;
  }
  
  .help-button {
    width: 45px;
    height: 45px;
    font-size: 20px;
    bottom: 15px;
    right: 15px;
  }
}
</style> 